<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>UDB Logo Editor</title>
    <style type="text/css">
     body { margin: 0px; padding: 0px }
    </style>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
	
    <script type="text/javascript">
    var map;
    var waypoints; // Waypoints on the map
    var cameras; // Camera markers on the map
    var infoWindow = new google.maps.InfoWindow();
    var infoWindowVisible = false;
    var waypointDefIndex;
    var waypointDefLen;
    var camerasDefIndex;
    var camerasDefLen;
    var overlayArray = []; // array of overlays on the map

    var homePoint = new google.maps.LatLng(37.4124664, -121.9950467);
    var planePoint;
    var planeAnglePoint;
    var planeAngle = 0;

    var homeMarker;
    var planeMarker;
    var planeAngleMarker;

    function getHomePoint(){
      try{
        var lat;
        lat = get_cookie("UDB_home_lat");
        var lng;
        lng = get_cookie("UDB_home_lng");
//alert(lat + "\n" + lng);
        if ((lat && lng) && !((lat == "null") || (lng == "null"))) {
          if (lng != "") { // both have to be non-null before we can use them
//alert("Setting home from cookie\n" + lat + "\n" + lng);
            homePoint = new google.maps.LatLng(lat, lng);
          }
        }
      } catch(err) {
        alert("Your browser security settings don't allow cookies. Home location won't be saved.\nTry using #define FIXED_ORIGIN_LOCATION {-1219950467, 374124664} in your waypoints file to set home location.");
      }
      setHomeMarker();
    }
	
	var oldHomePointLat;
	var oldHomePointLng;
	
    function setHomeMarker(){
      homeMarker = new google.maps.Marker({position: homePoint, draggable: true}); // TODO: Custom icon for home point
      google.maps.event.addListener(homeMarker, "dragend", homeMarkerMoved);
      google.maps.event.addListener(homeMarker, "dragstart", function() {
		infoWindow.close();
		oldHomePointLat = homePoint.lat();
		oldHomePointLng = homePoint.lng();
		oldPlanePointLat = planePoint.lat();
		oldPlanePointLng = planePoint.lng();
      });
    }

    function homeMarkerMoved(){
      //TODO: Ask if the waypoints should be updated or not.
      homePoint = homeMarker.getPosition();
      saveHomePoint();
	  
	  planePoint = new google.maps.LatLng(planePoint.lat() + homePoint.lat() - oldHomePointLat,
										planePoint.lng() + homePoint.lng() - oldHomePointLng);
	  savePlanePoint();
	  
	  planeAnglePoint = new google.maps.LatLng(planeAnglePoint.lat() + planePoint.lat() - oldPlanePointLat,
										planeAnglePoint.lng() + planePoint.lng() - oldPlanePointLng);
	  calcPlaneAngle();
	  savePlaneAnglePoint();
	  
      markerMoved();
    }

    function saveHomePoint(){
      set_cookie("UDB_home_lat", homePoint.lat());
      set_cookie("UDB_home_lng", homePoint.lng());
    }

    function getPlanePoint(){
      try{
        var lat;
        lat = get_cookie("UDB_plane_lat");
        var lng;
        lng = get_cookie("UDB_plane_lng");
		
//alert(lat + "\n" + lng);
        if ((lat && lng) && (lat != "null") && (lng != "null")) {
			planePoint = new google.maps.LatLng(lat, lng);
        }
		else {
			planePoint = new google.maps.LatLng(homePoint.lat()+0.001, homePoint.lng()+0.001);
		}
      } catch(err) {
        alert("Your browser security settings don't allow cookies. Plane location won't be saved.");
      }
      setPlaneMarker();
    }

    function getPlaneAnglePoint(){
      try{
        var lat;
        lat = get_cookie("UDB_plane_angle_lat");
        var lng;
        lng = get_cookie("UDB_plane_angle_lng");
		
//alert(lat + "\n" + lng);
        if ((lat && lng) && (lat != "null") && (lng != "null")) {
            planeAnglePoint = new google.maps.LatLng(lat, lng);
        }
		else {
			planeAnglePoint = new google.maps.LatLng(planePoint.lat()+0.001, planePoint.lng());
		}
      } catch(err) {
        alert("Your browser security settings don't allow cookies. Plane location won't be saved.");
      }
	  calcPlaneAngle();
      setPlaneAngleMarker();
    }

	var oldPlanePointLat;
	var oldPlanePointLng;
	
    function setPlaneMarker(){
	  var myImage = "http://gentlenav.googlecode.com/svn/trunk/Tools/UDB_Logo_Editor/plane.png";
      planeMarker = new google.maps.Marker({position: planePoint, draggable: true, icon:myImage});
      google.maps.event.addListener(planeMarker, "dragstart", function() {
		infoWindow.close();
		oldPlanePointLat = planePoint.lat();
		oldPlanePointLng = planePoint.lng();
	  });
      google.maps.event.addListener(planeMarker, "dragend", planeMarkerMoved);
	}
	
	function setPlaneAngleMarker(){
	  var myImage = "http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/greencirclemarker.png";
      planeAngleMarker = new google.maps.Marker({position: planeAnglePoint, draggable: true, icon:myImage});
      google.maps.event.addListener(planeAngleMarker, "dragend", planeAngleMarkerMoved);
    }
	  
    function planeMarkerMoved(){
      planePoint = planeMarker.getPosition();
	  
	  planeAnglePoint = new google.maps.LatLng(planeAnglePoint.lat() + planePoint.lat() - oldPlanePointLat,
										planeAnglePoint.lng() + planePoint.lng() - oldPlanePointLng);
	  calcPlaneAngle();
	  savePlaneAnglePoint();
	  
      savePlanePoint();
      markerMoved();
    }

    function planeAngleMarkerMoved(){
		planeAnglePoint = planeAngleMarker.getPosition();
		calcPlaneAngle();
		savePlaneAnglePoint();
		markerMoved();
	}
	
	function calcPlaneAngle(){
		var relPlanePt = absoluteToRelative(planePoint);
		var relPlaneAnglePt = absoluteToRelative(planeAnglePoint);
		var dx = relPlaneAnglePt.we-relPlanePt.we;
		var dy = relPlaneAnglePt.sn-relPlanePt.sn;
		var angle = Math.atan2(dy, dx);
		planeAngle = 90 - (angle * 180/Math.PI);
    }

    function savePlanePoint(){
      set_cookie("UDB_plane_lat", planePoint.lat());
      set_cookie("UDB_plane_lng", planePoint.lng());
    }

    function savePlaneAnglePoint(){
      set_cookie("UDB_plane_angle_lat", planeAnglePoint.lat());
      set_cookie("UDB_plane_angle_lng", planeAnglePoint.lng());
    }

	function showInfoWindow(anchor, content) {
	  infoWindowVisible = true;
	  infoWindow.setContent(content);
	  infoWindow.open(map, anchor);
	}
	
	function closeInfoWindow() {
	  infoWindow.close();
	  infoWindowVisible = false;
	}

    function initialize() {
      var myOptions = {
        zoom: 16,
        center: homePoint,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };
      map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	  
        google.maps.event.addListener(map, "click", mapClicked);
        reloadWaypointsHeader();
        map.setCenter(homePoint, 16);
        if (homePoint.lat() == 0 && homePoint.lng() == 0) {
          // The default home point needs a higher zoom level, out in the middle of the ocean. Images are only available from 9.
          map.setZoom(2);
        }
		do_resize();
    }

    function reloadWaypointsHeader(){
	  closeInfoWindow();
      getHomePoint();
      getPlanePoint();
	  getPlaneAnglePoint();
      reloadWaypoints();
      reloadCameraPoints();
      redrawOverlays();
    }      
/*
This event is fired when the user clicks on the map with the mouse. A click event passes different 
arguments based on the context of the click, and whether or not the click occured on a clickable 
overlay. If the click does not occur on a clickable overlay, the overlay argument is null and the 
latlng argument contains the geographical coordinates of the point that was clicked. If the user 
clicks on an overlay that is clickable (such as a google.maps.Marker, GPolygon, GPolyline, or 
GInfoWindow), the overlay argument contains the overlay object, while the overlaylatlng argument 
contains the coordinates of the clicked overlay. In addition, a click event is then also fired on 
the overlay itself.
*/
    function mapClicked(mouseEvent) {
      if (infoWindowVisible) {
		closeInfoWindow();
		return;
      }
	  var anchor = false;
      var l = mouseEvent.latLng;
      if (overlayArray) {
        for (i in overlayArray) {
          var p = overlayArray[i].get("position");
          if (p && l && p.equals(l)) {
          	anchor = overlayArray[i];
          	break;
          }
        }
      }
	  if (!anchor) {
		document.getElementById("waypoints_h").blur();
	  }
    }

    function markerMoved(){
      reloadWaypointsHeader();
      redrawOverlays();
    }

    function redrawOverlays(){
      var ep1;
      var ep2;

      clearOverlays();
      addOverlay(homeMarker);
      addOverlay(planeMarker);
      addOverlay(planeAngleMarker);
      addOverlay(new google.maps.Polyline({path: [planePoint, planeAnglePoint], strokeColor: "#FFFFFF", strokeWeight: 8}));
      addOverlay(new google.maps.Polyline({path: [planePoint, planeAnglePoint], strokeColor: "#66DD66", strokeWeight: 6}));
	  
      var cvDiv = document.getElementById('defaults_camera_view');
      if (cvDiv)
        cvDiv.innerHTML = writeCameraViewsSelect(); // TODO: selected value.
      if(document.form1.options_show_camera_points && document.form1.options_show_camera_points.checked){
        for (var i = 1; i < cameras.length; i++) { // we don't draw the camera point for CAM_VIEW_LAUNCH
          addOverlay(cameras[i]);
        }
      }
	  if (waypoints.length > 0) {
	    ep1 = planePoint;
        for (var i = 0; i < waypoints.length; i++) {
          addOverlay(waypoints[i]);
          ep2 = waypoints[i].getPosition();
          if(document.form1.options_show_camera_points && document.form1.options_show_camera_views.checked){
            var camView = getCameraViewpoint(waypoints[i].UDBcamView);
            if (camView) { // can't do much if we don't know this view point
              var polygon = new GPolygon([ ep1, camView.getPosition(), ep2, ep1 ], "#003ff3", 3, 0.5, "#0000ff", 0.2); // make sure to close the polygon
              addOverlay(polygon);
            }
          }
          var polyline = new google.maps.Polyline({path: [ep1, ep2], strokeColor: "#ff0000", strokeWeight: 10});
          addOverlay(polyline);
          ep1 = ep2;
        }
	  }
    }

    function getCameraViewpoint(name)
    {
      for(var i = 0; i < cameras.length; i++) { // is there a better way?
        if (cameras[i].UDBname == name)
        {
          return cameras[i];
        }
      }
      return null;
    }

    function reloadCameraPoints(){
      camerasDefIndex = waypointDefIndex;
      camerasDefLen = 0;
      clearCameraPoints();
      var r = /^\/\/Camera points/gmi;
      var m = r.exec(document.form1.waypoints_h.value);
      if (m == null) {
        //alert("No start of camera points found.");
        return;
      }
      camerasDefIndex = m.index;
      r = /^\/\/End of camera points/gmi;
      m = r.exec(document.form1.waypoints_h.value);
      if (m == null) {
        alert("No end to camera points found.");
        return;
      }
      camerasDefLen = m.index - camerasDefIndex + 22;
      var def = document.form1.waypoints_h.value.substring(camerasDefIndex, camerasDefIndex + camerasDefLen);
      var r = /(?:\s*)#define(?:\s+)(\S+)(?:\s*){\s*(-?\d+)\s*,\s*(-?\d+)\s*,\s*(\d+)\s*}/gi; 

      while ((m = r.exec(def)) != null) {// match each of the camera points in the definition found above
        var name = m[1]; // TODO: variants of a name (_REL / _ABS)
        var lng = parseInt(m[2])/10000000;
        var lat = parseInt(m[3])/10000000;
        var alt = m[4];
        addCameraPoint(name, lat, lng, alt);
      }
    }
	
	var logoInstructions;
	var logoInstructionIndex;
	
	var logoAngle;
	var logoLocationX;
	var logoLocationY;
	var logoLocationZ;
	
	var savedLogoAngle;
	var savedLogoLocationX;
	var savedLogoLocationY;
	var savedLogoLocationZ;
	
	var logoLastLocationX;
	var logoLastLocationY;
	
	var logoFlags = new Array();
	var logoTurtleNum;
	var logoPenState;
	var logoStackTypes = new Array();
	var logoStackReturnIndecies = new Array();
	var logoStackArgs = new Array();
	var logoStackIndex;
	var logoSwitchVal = 0;
	
    function reloadWaypoints(){
      clearWaypoints();
	  
      var rUseFixedOrigin = /^[^/\S]*#define\s*USE_FIXED_ORIGIN\s*([01])/m;
      var m = rUseFixedOrigin.exec(document.form1.waypoints_h.value);
	  if (m && m[1] == 1) {
		// TODO: Load home waypoint from #define FIXED_ORIGIN_LOCATION   { -1219950467, 374124664, 13.0 }
		// If no home waypoint, or if #define USE_FIXED_ORIGIN 1
		///var rFixedOrigin = /^[^/\S]*#define\s*FIXED_ORIGIN_LOCATION\s*{\s*(-?\d+),\s*(-?\d+)\s*(?:,\s*\d+\.?\d*)}/sm;
		var rFixedOrigin = /^[^/\S]*#define\s*FIXED_ORIGIN_LOCATION\s*{\s*(-?\d+),\s*(-?\d+)\s*(?:,\s*\d+\.?\d*)}/m;
		var m = rFixedOrigin.exec(document.form1.waypoints_h.value);
		if (m != null) {
			///alert ("Fixed origin found!");
			var lng = parseInt(m[1])/10000000;
			var lat = parseInt(m[2])/10000000;
			homePoint = new google.maps.LatLng(lat, lng);
			setHomeMarker();
			saveHomePoint();          
		}
	  }
////      var rWaypointsDef = /^(?:\s*[^/\S]*\s*)const\s+struct\s+logoInstructionDef\s+instructions\s*\[\s*\]\s*=\s*{\s*([^}*)}/sim;
      var rWaypointsDef = /^(?:\s*[^/\S]*\s*)const\s+struct\s+logoInstructionDef\s+instructions\s*\[\s*\]\s*=\s*{\s*([^}]*)}/im;
      var m = rWaypointsDef.exec(document.form1.waypoints_h.value);
	  var def;
	  
      if (m == null) {
		def = document.form1.waypoints_h.value;
      }
	  else {
        def = m[1];
	  }
	  
///alert(def);
      // waypointDefIndex = m.index;
      waypointDefLen = def.length;
      rWaypoint = /^\s*([A-Z_]+)(?:\s*\(\s*([0-9A-Z_-]+)(?:\s*,\s*([0-9A-Z_-]+))?\s*\))?/gm;
      var ma; // this seems to solve strange behavior on Chrome...
	  logoInstructions = new Array();
      while ((ma = rWaypoint.exec(def)) != null) {
		logoInstructions.push(ma);
	  }
// match each of the waypoints in the definition found above
///var s = "Length :" + ma.length + "\n";
///for (var i = 0; i < ma.length; i++){
///s += i + ":" + ma[i] + "|" + ma[i].index + "\n";
///}
///alert(s);
	  logoInitialize();
	  while ( 1 ) {
	    ma = logoInstructions[logoInstructionIndex];
		var cmd = ma[1];
        var arg1 = parseInt(ma[2]);
        var arg2 = parseInt(ma[3]);
		if (isNaN(arg1)) arg1 = ma[2];
		if (isNaN(arg2)) arg2 = ma[3];
		logoHandleCommand(cmd, arg1, arg2);
		logoInstructionIndex++;
		if (logoInstructionIndex >= logoInstructions.length) break;
      }
    }
	
	
	function startOfSubroutine(subName)
	{
		for (i = 0; i < logoInstructions.length; i++) {
			ma = logoInstructions[i];
			var cmd = ma[1];
			var arg1 = ma[2];
			if (cmd == "TO" && arg1 == subName) return i;
		}
		return logoInstructions.length;
	}
	
	
	function skipToEnd()
	{
		var depth = 0;
		
		logoInstructionIndex++;
		
		while (logoInstructionIndex < logoInstructions.length) {
			ma = logoInstructions[logoInstructionIndex];
			var cmd = ma[1];
			if (cmd == "END" && depth == 0) {
				return;
			}
			else if (cmd == "END" && depth > 0) depth--;
			else if (cmd == "REPEAT") depth++;
			else if (cmd == "REPEAT_PARAM") depth++;
			else if (cmd == "REPEAT_FOREVER") depth++;
			else if (cmd.indexOf("IF_PARAM_") === 0) depth++;
			
			logoInstructionIndex++;
		}
	}
	
	
	function get_current_stack_parameter_frame_index()
	{
		var ind = logoStackIndex-1;
		while(ind >= 0)
		{
			if (logoStackTypes[ind] == 0)
			{
				return ind;
			}
			ind--;
		}
		return -1;
	}
	
	
	function logoInitialize() {
		logoStackIndex = 1;
		logoStackTypes[0] = 0;
		logoStackReturnIndecies[0] = logoInstructions.length;
		logoStackArgs[0] = 0;
		
		logoInstructionIndex = 0;
		
		logoPlaneAngle = logoAngle = planeAngle;
		logoFlags = [];
		logoTurtleNum = 0;
		logoPenState = 0;
		logoLocationZ = 0;
		var relPlane = absoluteToRelative(planePoint);
		logoLocationX = logoLastLocationX = relPlane.we;
		logoLocationY = logoLastLocationY = relPlane.sn;
		logoRepeatIndex = 0;
		
		savedLogoAngle = logoAngle;
		savedLogoLocationX = logoLocationX;
		savedLogoLocationY = logoLocationY;
		savedLogoLocationZ = logoLocationZ;
	}
	
	function logoHandleCommand(cmd, arg1, arg2) {
		// alert(cmd + "[" + arg1 + ", " + arg2 + "]\n");
		
		if (cmd == "SET_TURTLE") {
			// FIXME: Add real support for moving the camera position
			if (arg1 == "PLANE")
				logoTurtleNum = 0;
			else
				logoTurtleNum = 1;
		}
		else if (logoTurtleNum == 0) {
		
			switch (cmd) {
				case "FD_PARAM":
				case "BK_PARAM":
				case "RT_PARAM":
				case "LT_PARAM":
				case "SET_ANGLE_PARAM":
				case "EAST_PARAM":
				case "WEST_PARAM":
				case "NORTH_PARAM":
				case "SOUTH_PARAM":
				case "SET_X_POS_PARAM":
				case "SET_Y_POS_PARAM":
				case "SET_ALT_PARAM":
				case "ALT_UP_PARAM":
				case "ALT_DOWN_PARAM":
				case "SET_ALT_PARAM":
				case "REPEAT_PARAM":
					var i = get_current_stack_parameter_frame_index();
					if (i >= 0) arg1 = logoStackArgs[i];
					break;
				case "DO_PARAM":
				case "EXEC_PARAM":
					var i = get_current_stack_parameter_frame_index();
					if (i >= 0) arg2 = logoStackArgs[i];
					break;
			}
			
			switch (cmd) {
				case "REPEAT":
				case "REPEAT_PARAM":
					if (logoStackIndex < 12)
					{
						logoStackTypes[logoStackIndex] = 1;
						logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
						logoStackArgs[logoStackIndex] = arg1;
						logoStackIndex++;
					}
					break;
				case "REPEAT_FOREVER":
					if (logoRepeatIndex < 12)
					{
						logoStackTypes[logoStackIndex] = 1;
						logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
						logoStackArgs[logoStackIndex] = 1; // Allow repeating forever loops more than once
						logoStackIndex++;
					}
					break;
				case "END":
					if (logoStackIndex > 0)
					{
						logoStackIndex-- ;
						if (logoStackTypes[logoStackIndex] == 1)
						{
							if ( logoStackArgs[logoStackIndex] > 1)
							{
								logoStackArgs[logoStackIndex]-- ;
								logoInstructionIndex = logoStackReturnIndecies[logoStackIndex] ;
								logoStackIndex++ ;
							}
						}
						else {
							logoInstructionIndex = logoStackReturnIndecies[logoStackIndex] ;
						}
					}
					else {
						logoInstructionIndex = logoInstructions.length; // End logo program
					}
					break;
				case "RETURN":
					if (logoStackIndex > 0)
					{
						logoStackIndex-- ;
						while (logoStackIndex && logoStackTypes[logoStackIndex] == 1)
						{
							logoStackIndex-- ;
						}
						logoInstructionIndex = logoStackReturnIndecies[logoStackIndex] ;
					}
					else {
						logoInstructionIndex = logoInstructions.length; // End logo program
					}
					break;
				
				case "TO":
					logoInstructionIndex = logoInstructions.length; // End logo program
					break;
				
				case "EXEC":
				case "EXEC_ARG":
				case "EXEC_PARAM":
					logoStackIndex = 0;
					logoInstructionIndex = logoInstructions.length;
				case "DO":
				case "DO_ARG":
				case "DO_PARAM":
					if (logoStackIndex < 12)
					{
						logoStackTypes[logoStackIndex] = 0;
						logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
						logoStackArgs[logoStackIndex] = arg2;
						logoStackIndex++;
					}
					logoInstructionIndex = (arg1 == 0) ? 0 : startOfSubroutine(arg1);
					break;
					
				case "IF_PARAM_EQ":
					if (logoStackIndex < 12)
					{
						var i = get_current_stack_parameter_frame_index();
						if (i >= 0) {
							var param = logoStackArgs[i];
							if (param == arg1) {
								if (logoStackIndex < 12)
								{
									logoStackTypes[logoStackIndex] = 1;
									logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
									logoStackArgs[logoStackIndex] = 1;
									logoStackIndex++;
								}
							}
							else {
								skipToEnd();
							}
						}
					}
					break;
				case "IF_PARAM_NE":
					if (logoStackIndex < 12)
					{
						var i = get_current_stack_parameter_frame_index();
						if (i >= 0) {
							var param = logoStackArgs[i];
							if (param != arg1) {
								if (logoStackIndex < 12)
								{
									logoStackTypes[logoStackIndex] = 1;
									logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
									logoStackArgs[logoStackIndex] = 1;
									logoStackIndex++;
								}
							}
							else {
								skipToEnd();
							}
						}
					}
					break;
				case "IF_PARAM_GT":
					if (logoStackIndex < 12)
					{
						var i = get_current_stack_parameter_frame_index();
						if (i >= 0) {
							var param = logoStackArgs[i];
							if (param > arg1) {
								if (logoStackIndex < 12)
								{
									logoStackTypes[logoStackIndex] = 1;
									logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
									logoStackArgs[logoStackIndex] = 1;
									logoStackIndex++;
								}
							}
							else {
								skipToEnd();
							}
						}
					}
					break;
				case "IF_PARAM_LT":
					if (logoStackIndex < 12)
					{
						var i = get_current_stack_parameter_frame_index();
						if (i >= 0) {
							var param = logoStackArgs[i];
							if (param < arg1) {
								if (logoStackIndex < 12)
								{
									logoStackTypes[logoStackIndex] = 1;
									logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
									logoStackArgs[logoStackIndex] = 1;
									logoStackIndex++;
								}
							}
							else {
								skipToEnd();
							}
						}
					}
					break;
				case "IF_PARAM_GE":
					if (logoStackIndex < 12)
					{
						var i = get_current_stack_parameter_frame_index();
						if (i >= 0) {
							var param = logoStackArgs[i];
							if (param >= arg1) {
								if (logoStackIndex < 12)
								{
									logoStackTypes[logoStackIndex] = 1;
									logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
									logoStackArgs[logoStackIndex] = 1;
									logoStackIndex++;
								}
							}
							else {
								skipToEnd();
							}
						}
					}
					break;
				case "IF_PARAM_LE":
					if (logoStackIndex < 12)
					{
						var i = get_current_stack_parameter_frame_index();
						if (i >= 0) {
							var param = logoStackArgs[i];
							if (param <= arg1) {
								if (logoStackIndex < 12)
								{
									logoStackTypes[logoStackIndex] = 1;
									logoStackReturnIndecies[logoStackIndex] = logoInstructionIndex;
									logoStackArgs[logoStackIndex] = 1;
									logoStackIndex++;
								}
							}
							else {
								skipToEnd();
							}
						}
					}
					break;
				
				case "HOME":
					logoLocationX = logoLocationY = 0;
					logoAngle = 0;
					logoAddWaypoint();
					break;
				case "FD":
				case "FD_PARAM":
					logoLocationX += Math.cos(-(logoAngle-90) * Math.PI/180) * arg1;
					logoLocationY += Math.sin(-(logoAngle-90) * Math.PI/180) * arg1;
					logoAddWaypoint();
					break;
				case "BK":
				case "BK_PARAM":
					logoLocationX -= Math.cos(-(logoAngle-90) * Math.PI/180) * arg1;
					logoLocationY -= Math.sin(-(logoAngle-90) * Math.PI/180) * arg1;
					logoAddWaypoint();
					break;
				case "SET_POS":
					logoLocationX = arg1;
					logoLocationY = arg2;
					logoAddWaypoint();
					break;
				case "SET_ABS_POS":
					logoLocationX = arg1;
					logoLocationY = arg2;
					logoAddAbsWaypoint();
					break;
				case "USE_CURRENT_POS":
					logoLocationX = logoLastLocationX;
					logoLocationY = logoLastLocationY;
					logoAddWaypoint();
					break;
				
				case "RT":
				case "RT_PARAM":
					logoAngle += arg1;
					while (logoAngle < 0) logoAngle += 360 ;
					logoAngle = logoAngle % 360 ;
					break;
				case "LT":
				case "LT_PARAM":
					logoAngle -= arg1;
					while (logoAngle < 0) logoAngle += 360 ;
					logoAngle = logoAngle % 360 ;
					break;
				case "SET_ANGLE":
				case "SET_ANGLE_PARAM":
					logoAngle = arg1;
					break;
				case "USE_CURRENT_ANGLE":
					logoAngle = logoPlaneAngle;
					break;
				case "USE_ANGLE_TO_GOAL":
					logoAngle = angle_between_points(logoLastLocationX, logoLastLocationY, logoLocationX, logoLocationY);
					break;
				
				case "EAST":
				case "EAST_PARAM":
					logoLocationX += arg1;
					break;
				case "WEST":
				case "WEST_PARAM":
					logoLocationX -= arg1;
					break;
				case "SET_X_POS":
				case "SET_X_POS_PARAM":
					logoLocationX = arg1;
					break;
				
				case "NORTH":
				case "NORTH_PARAM":
					logoLocationY += arg1;
					break;
				case "SOUTH":
				case "SOUTH_PARAM":
					logoLocationY -= arg1;
					break;
				case "SET_Y_POS":
				case "SET_Y_POS_PARAM":
					logoLocationY = arg1;
					break;
				
				case "ALT_UP":
				case "ALT_UP_PARAM":
					logoLocationZ += arg1;
					break;
				case "ALT_DOWN":
				case "ALT_DOWN_PARAM":
					logoLocationZ -= arg1;
					break;
				case "SET_ALT":
				case "SET_ALT_PARAM":
					logoLocationZ = arg1;
					break;
				
				case "FLAG_ON":
					logoFlags[arg1] = 1;
					break;
				case "FLAG_OFF":
					logoFlags[arg1] = 0;
					break;
				case "FLAG_TOGGLE":
					logoFlags[arg1] = (logoFlags[arg1] == 1) ? 0 : 1;
					break;
				
				case "PEN_UP":
					logoPenState++;
					break;
				case "PEN_DOWN":
					if (logoPenState > 0) {
						logoPenState--;
					}
					logoAddWaypoint();
					break;
				case "PEN_TOGGLE":
					if (logoPenState > 0) {
						logoPenState = 0;
						logoAddWaypoint();
					}
					else {
						logoPenState = 1;
					}
					break;
				case "PARAM_SET":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = arg1;
					break;
				case "PARAM_ADD":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] += arg1;
					break;
				case "PARAM_SUB":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] -= arg1;
					break;
				case "PARAM_MUL":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] *= arg1;
					break;
				case "PARAM_DIV":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] /= arg1;
					break;
					
				case "PARAM_LOAD_DIST_TO_GOAL":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] =
						Math.sqrt(Math.pow(logoLocationX - logoLastLocationX, 2) + Math.pow(logoLocationY - logoLastLocationY,2));
					break;
				case "PARAM_LOAD_ALT":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = logoLocationZ;
					break;
				case "PARAM_LOAD_CURRENT_ANGLE":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = logoPlaneAngle;
					break;
				case "PARAM_LOAD_ANGLE_TO_GOAL":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] =
						angle_between_points(logoLastLocationX, logoLastLocationY, logoLocationX, logoLocationY);
					break;
				case "PARAM_LOAD_REL_ANGLE_TO_GOAL":
					var ind = get_current_stack_parameter_frame_index();
					var a = angle_between_points(logoLastLocationX, logoLastLocationY, logoLocationX, logoLocationY);
					a = (a - logoPlaneAngle + 360) % 360;
					if (a > 180) a = a-360;
					if (ind >= 0) logoStackArgs[ind] = a;
					break;
				case "PARAM_LOAD_WIND_ANGLE":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = 0;
					break;
				case "PARAM_LOAD_GROUND_SPEED":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = 10;
					break;
				case "PARAM_LOAD_AIR_SPEED":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = 10;
					break;
				case "PARAM_LOAD_WIND_SPEED":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = 0;
					break;
				case "PARAM_LOAD_LOGO_SWITCH_STATE":
					var ind = get_current_stack_parameter_frame_index();
					if (ind >= 0) logoStackArgs[ind] = logoSwitchVal;
					logoSwitchVal = 1-logoSwitchVal;
					break;
				
				case "SAVE_TURTLE_STATE":
					savedLogoAngle = logoAngle;
					savedLogoLocationX = logoLocationX;
					savedLogoLocationY = logoLocationY;
					savedLogoLocationZ = logoLocationZ;
					break;
				case "LOAD_TURTLE_STATE":
					logoAngle = savedLogoAngle;
					logoLocationX = savedLogoLocationX;
					logoLocationY = savedLogoLocationY;
					logoLocationZ = savedLogoLocationZ;
					break;
				
				default:
					// alert("Unknown command: " + cmd + "(" + arg1 + ", " + arg2 + ")");
					break;
			}
		}
	}
	
	
	function logoAddWaypoint() {
		if (logoPenState == 0) {
			var flagStr = "";
			for (var f in logoFlags) {
				if (logoFlags[f] == 1) {
					flagStr += f + " + ";
				}
			}
			
			if (flagStr == "") flagStr = "F_NORMAL";
			
			if (logoLocationX != logoLastLocationX || logoLocationY != logoLastLocationY) {
				addWaypoint(logoLocationY, logoLocationX, logoLocationZ, flagStr, 0);
				logoPlaneAngle = angle_between_points(logoLastLocationX, logoLastLocationY, logoLocationX, logoLocationY);
				logoLastLocationY = logoLocationY;
				logoLastLocationX = logoLocationX;
			}
		}
	}
	
	
	
	function logoAddAbsWaypoint() {
		var latLng = new google.maps.LatLng(logoLocationY/10000000, logoLocationX/10000000);
		var relPlanePt = absoluteToRelative(latLng);
		logoLocationX = relPlanePt.we;
		logoLocationY = relPlanePt.sn;
		logoAddWaypoint();
	}
	
	
	
    function clearWaypoints(){
      waypoints = new Array();
    }
	
	function angle_between_points(x1, y1, x2, y2) {
		var dx = x2-x1;
		var dy = y2-y1;
		var a = 90 - Math.atan2(dy,dx) * 360/(Math.PI * 2);
		return a;
	}
	
    function clearCameraPoints(){
      cameras = new Array();
      cameras[0] = new google.maps.Marker({position: homePoint});
      cameras[0].UDBName = "CAM_VIEW_LAUNCH";
      cameras[0].UDBRelName = "CAM_VIEW_LAUNCH_REL";
      cameras[0].UDBAbsName = "CAM_VIEW_LAUNCH_ABS";
    }

    // Removes the overlays from the map, but keeps them in the array
    function removeOverlays(){
      if (overlayArray) {
        for (i in overlayArray) {
        	overlayArray[i].setMap(null);
        }
      }
    }

    // Removes the overlays from the map, and empties the overlaysArray
    function clearOverlays(){
      removeOverlays();
      overlayArray.length = 0;      
    }
  
    function addOverlay(overlay) {
      overlay.setMap(map);
      overlayArray.push(overlay);
    }

    function relativeCordinates(){} // placeholder to make an object
    
    function absoluteToRelative(latLng)
    {
      var l = new relativeCordinates(); // object to hold relative offsets
      l.we = Math.round((latLng.lng() - homePoint.lng()) * (Math.cos((homePoint.lat()/360)*2*Math.PI)) / 0.000009); // how many meters south (negative) or north of home point
      l.sn = Math.round((latLng.lat() - homePoint.lat()) / 0.000009); // how many meters west (negative) or east of home point
      return l;
    }

    function relativeToAbsolute(l)
    {
        var homeLat = homePoint.lat();
        var homeLng = homePoint.lng();
        var lat = (homeLat + (l.sn * 0.000009)); // how many meters west (negative) or east of home point
        var lng = (homeLng + ((l.we * 0.000009)/(Math.cos((homeLat/360)*2*Math.PI)))); // how many meters south (negative) or north of home point
        return new google.maps.LatLng(lat, lng);
    }
    
    function addWaypoint(lat, lng, alt, flags, camView){
      var index = waypoints.length;
	  var myImage;
	  if (index < 99) {
		myImage = "http://gmaps-samples.googlecode.com/svn/trunk/markers/red/marker" + (index+1) + ".png"; // TODO: Set image based on flags
      }
	  else {
		myImage = "http://gmaps-samples.googlecode.com/svn/trunk/markers/red/blank.png";
	  }
	  var latlng;
      if(flags.indexOf("F_ABSOLUTE") > -1) {
        latlng = new google.maps.LatLng(lat/10000000, lng/10000000);
      } else { // relative waypoints
        var l = new relativeCordinates();
        l.we = lng;
        l.sn = lat;        
        latlng = relativeToAbsolute(l);
      }
      var marker = new google.maps.Marker({position: latlng, draggable: false, icon:myImage});
      marker.UDBIndex = index;
      marker.UDBalt = alt;
      marker.UDBflags = flags;
	  /*
      marker.UDBcamView = camView;
      if((marker.UDBcamView.indexOf("_ABS") == marker.UDBcamView.length - 4) | (marker.UDBcamView.indexOf("_REL") == marker.UDBcamView.length - 4)) {
    	  marker.UDBcamView = marker.UDBcamView.substr(0, marker.UDBcamView.length - 4);
      }
	  */
      waypoints[waypoints.length] = marker;
	  /*
      google.maps.event.addListener(marker, "dragstart", function() {
        closeInfoWindow();
      });
      google.maps.event.addListener(marker, "dragend", markerMoved);
	  */
      google.maps.event.addListener(marker, "click", markerClick);
    }

    function addCameraPointG(latLng){
      addCameraPoint(document.form1.options_camera_view_name.value, latLng.lat(), latLng.lng(), 0);
    }

    function addCameraPoint(name, lat, lng, alt){
      if(name.indexOf("_ABS") == name.length - 4){
            name = name.substr(0, name.length - 4);
      }
      if(name.indexOf("_REL") == name.length - 4){
            name = name.substr(0, name.length - 4);
      }
//TODO: Make sure name is unique
      var index = cameras.length;
      var myIcon = new GIcon(baseIcon);
      myIcon.image = "http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/marker" + index + ".png";
      var latlng = new google.maps.LatLng(lat, lng);
      var marker = new google.maps.Marker({position: latlng, draggable: false, icon:myIcon});
      marker.UDBname = name;
      marker.UDBrelName = name + "_REL";
      marker.UDBabsName = name + "_ABS";
      marker.UDBalt = alt;
      cameras[cameras.length] = marker;
	  /*
      google.maps.event.addListener(marker, "dragstart", function() {
        closeInfoWindow();
      });
      google.maps.event.addListener(marker, "dragend", markerMoved);
      google.maps.event.addListener(marker, "click", cameraClick);
	  */
    }

    var wpEditIndex;
    var wpEditAlt;
    var wpEditFlags;
    var wpEditCamView;

    function cameraClick(){
      showInfoWindow(this, this.UDBName + "<br />(" + this.UDBRelName + "<br />" + this.UDBAbsName +")");
    }

    function markerClick(){
      wpEditIndex = this.UDBIndex;
      wpEditAlt = this.UDBalt;
      wpEditFlags = this.UDBflags;
      wpEditCamView = this.UDBcamView;
      var s = "<form name='editMarker' value='editMarker' action='javascript:void(0);'><table>";
      s += "<tr><td colspan='2'>Waypoint #" + (wpEditIndex + 1) + "</td></tr>";
      s += "<tr><td colspan='2'>Altitude: <input disabled type='text' name='alt' id='alt' value='" + wpEditAlt + "'/></td></tr>";
      s += "<tr><td>";
      s += writeFlagsCode(wpEditFlags);
      s += "</td></tr>";
      s += "<tr><td colspan='2'>CameraView: <input disabled type='text' name='camView' id='camView' value='" + wpEditCamView + "'/></td></tr>";
      s += "</table></form>";
      showInfoWindow(this, s);
    }

    function writeFlagsCode(flags)
    {
        var s = "<table>";
        s += "<tr>";
        s += "<td><input disabled type='checkbox' name='flag_f_normal' id='flag_f_normal'";
        if (flags.indexOf("F_NORMAL") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_NORMAL</td>";
        s += "<td><input disabled type='checkbox' name='flag_f_cross_track' id='flag_f_cross_track'";
        if (flags.indexOf("F_CROSS_TRACK") > -1) {
          s += " checked='YES' " 
        }
        s += "/></td><td>F_CROSS_TRACK</td>";
        s += "</tr>";
        s += "<tr>";
        s += "<td><input disabled type='checkbox' name='flag_f_inverted' id='flag_f_inverted'";
        if (flags.indexOf("F_INVERTED") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_INVERTED</td>";
        s += "<td><input disabled type='checkbox' name='flag_f_hover' id='flag_f_hover'";
        if (flags.indexOf("F_HOVER") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_HOVER</td>";
        s += "</tr>";
        s += "<tr>";
        s += "<td><input disabled type='checkbox' name='flag_f_land' id='flag_f_land'";
        if (flags.indexOf("F_LAND") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_LAND</td>";
        s += "<td><input disabled type='checkbox' name='flag_f_loiter' id='flag_f_loiter'";
        if (flags.indexOf("F_LOITER") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_LOITER</td>";
        s += "</tr>";
        s += "<tr>";
        s += "<td><input disabled type='checkbox' name='flag_f_trigger' id='flag_f_trigger'";
        if (flags.indexOf("F_TRIGGER") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_TRIGGER</td>";
        s += "<td><input disabled type='checkbox' name='flag_f_altitude_goal' id='flag_f_altitude_goal'";
        if (flags.indexOf("F_ALTITUDE_GOAL") > -1) {
            s += " checked='YES' " 
        }
        s += "/></td><td>F_ALTITUDE_GOAL</td>";
        s += "</tr>";
        s += "</table>";
        return s;
    }

    function writeCameraViewsSelect(selected)
    {
      var s = "<select name='camera_view' id='camera_view'>";
      for(var i = 0; i < cameras.length; i++){
          var name = cameras[i].UDBName;
          s += "<option ";
          if (name == selected)
            s += "selected='y'";
          s += ">" + name + "</option>";
      }
      s += "</select>";
      return s;
    }

    function set_cookie ( name, value, exp_y, exp_m, exp_d, path, domain, secure ){
      try {
        var cookie_string = name + "=" + escape ( value );
        if (exp_y) {
          var expires = new Date ( exp_y, exp_m, exp_d );
          cookie_string += "; expires=" + expires.toGMTString();
        }
        if (path)
          cookie_string += "; path=" + escape ( path );
        if (domain)
          cookie_string += "; domain=" + escape ( domain );
        if (secure)
          cookie_string += "; secure";
        document.cookie = cookie_string;
        try {
          localStorage.setItem(name, value);
        } catch (err) {
      	  alert("Error: Couldn't use local storage either!");
      	}
      } catch(err) {
        alert("Error saving cookie.\n" + err);
      }
    }

    function get_cookie ( cookie_name ) {
      var results = document.cookie.match ( '(^|;) ?' + cookie_name + '=([^;]*)(;|$)' );
      if (results)
      {
        return (unescape(results[2]));
      }
      try {
        results = localStorage.getItem(cookie_name);
        return (unescape(results));
      } catch (err) { }
      return null;
    }

    function getRadioValue(radio) {
      for (var i=0; i < radio.length; i++) {
        if (radio[i].checked) {
          return radio[i].value;
        }
      }
    }


function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function replaceSelection (input, replaceString) {
	if (input.setSelectionRange) {
		var selectionStart = input.selectionStart;
		var selectionEnd = input.selectionEnd;
		input.value = input.value.substring(0, selectionStart)+ replaceString + input.value.substring(selectionEnd);
    
		if (selectionStart != selectionEnd){ 
			setSelectionRange(input, selectionStart, selectionStart + 	replaceString.length);
		}else{
			setSelectionRange(input, selectionStart + replaceString.length, selectionStart + replaceString.length);
		}

	}else if (document.selection) {
		var range = document.selection.createRange();

		if (range.parentElement() == input) {
			var isCollapsed = range.text == '';
			range.text = replaceString;

			 if (!isCollapsed)  {
				range.moveStart('character', -replaceString.length);
				range.select();
			}
		}
	}
}


// We are going to catch the TAB key so that we can use it, Hooray!
function catchTab(item,e){
	if(navigator.userAgent.match("Gecko")){
		c=e.which;
	}else{
		c=e.keyCode;
	}
	if(c==9){
		replaceSelection(item,String.fromCharCode(9));
		setTimeout("document.getElementById('"+item.id+"').focus();",0);	
		return false;
	}
		    
}


function getActualStyle(a) {
	if (document.defaultView && document.defaultView.getComputedStyle){
		return document.defaultView.getComputedStyle(a,"");
	}
	else
		return a.style;
}


// FIXME: Replace magic numbers with live values of frame margins, etc.
function do_resize() {
	try {
		var htmlheight = document.body.parentNode.clientHeight;
		var htmlwidth = document.body.parentNode.clientWidth;
		
		var wframe = document.getElementById("waypoints_h");
		wframe.style.height = (htmlheight - 85) + "px";
		var wstyle = getActualStyle(wframe);
		var wwidth = wstyle.getPropertyValue("width").replace(/px/, "");
		
		var mframe = document.getElementById("map_canvas");
		mframe.style.height = (htmlheight - 15) + "px";
		mframe.style.width = (htmlwidth - wwidth - 30) + "px";
	}
	catch(err) {
		// alert(err);
	}
}

    </script>
  </head>

  <body onload="initialize()" onresize="do_resize()">
   <form name="form1" id="form1" method="post" action="javascript:void(0)">
	<table border="0">
	<tr>
	<td valign="top">
		<h2>UDB Logo Editor <a target="_blank" href="http://code.google.com/p/gentlenav/source/browse/trunk/MatrixPilot/flightplan-logo.h#69">[Reference]</a></h2>
        <textarea name="waypoints_h" id="waypoints_h" rows="60" cols="55" wrap="off" onBlur="reloadWaypointsHeader();" onkeydown="return catchTab(this,event)" style="font-family: monospace;">
//////////////////////////////////////////////////
// UDB Logo Simulation
// 
// The pink pin with a dot in the middle is the
// origin.
// 
// The plane icon simulates the location of the
// plane when you switch into waypoint mode.
// 
// The green circle simulates the direction that
// the plane is moving when you switch into
// waypoint mode.


//////////////////////////////////////////////////
// UDB LOGO Navigation Parameters

#define WAYPOINT_RADIUS                     25

#define USE_FIXED_ORIGIN                    0
#define FIXED_ORIGIN_LOCATION {-1219950467, 374124664, 2.0}
// A point in Baylands Park in Sunnyvale, CA


//////////////////////////////////////////////////
// UDB LOGO Program

#define SQUARE			1
#define CIRCLE			2

const struct logoInstructionDef instructions[] = {

DO_ARG(SQUARE, 100)

HOME

DO_ARG(CIRCLE, 100)

END



TO (SQUARE)
	REPEAT(4)
		FD_PARAM
		RT(90)
	END
END


TO (CIRCLE)
	PARAM_DIV(5)
	REPEAT(18)
		FD_PARAM
		RT(20)
	END
END

} ;
</textarea>
	</td>
	<td valign="top">
		<div id="map_canvas" style="width: 800px; height: 800px"></div>
	</td></tr>
	</table>   
   </form>
  </body>
</html>
